#include <U8g2lib.h>      // OLED驱动库
#include <WiFi.h>         // WiFi功能
#include "time.h"         // 时间函数

// 软件I2C引脚配置
#define SDA_PIN 25
#define SCL_PIN 26

// 红绿灯引脚配置
#define RED_PIN 12
#define YELLOW_PIN 13
#define GREEN_PIN 14

// 按钮引脚配置
#define BUTTON_PIN 15

// WiFi配置
const char* ssid = "CMCC-fp9k";
const char* password = "Wxz9au<6";

// NTP配置
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600; // 北京时间 (UTC+8)
const int daylightOffset_sec = 0;    // 无夏令时

// 创建软件I2C OLED实例
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(
  U8G2_R0,           // 旋转方向
  SCL_PIN,           // 时钟引脚
  SDA_PIN,           // 数据引脚
  U8X8_PIN_NONE      // 无复位引脚
);

// 红绿灯状态枚举
enum TrafficLightState {
  RED_STATE,
  GREEN_STATE,
  YELLOW_STATE
};

// 全局变量
TrafficLightState currentState = RED_STATE;
TrafficLightState displayState = RED_STATE; // 单独用于显示的状态
bool manualMode = false;
int buttonState = HIGH;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
int debounceDelay = 50;
bool timeSynced = false;  // 时间是否已同步
bool wifiConnected = false; // WiFi连接状态
unsigned long lastWiFiCheck = 0; // 上次检查WiFi时间
int wifiRSSI = 0; // WiFi信号强度

// 中文编码定义
const uint8_t RED_CHINESE[] = {0xE7, 0xBA, 0xA2, 0xE7, 0x81, 0xAF, 0};    // 红灯
const uint8_t GREEN_CHINESE[] = {0xE7, 0xBB, 0xBF, 0xE7, 0x81, 0xAF, 0};  // 绿灯
const uint8_t YELLOW_CHINESE[] = {0xE9, 0xBB, 0x84, 0xE7, 0x81, 0xAF, 0}; // 黄灯
const uint8_t AUTO_MODE[] = {0xE8, 0x87, 0xAA, 0xE5, 0x8A, 0xA8, 0xE6, 0xA8, 0xA1, 0xE5, 0xBC, 0x8F, 0}; // 自动模式
const uint8_t MANUAL_MODE[] = {0xE6, 0x89, 0x8B, 0xE5, 0x8A, 0xA8, 0xE6, 0xA8, 0xA1, 0xE5, 0xBC, 0x8F, 0}; // 手动模式

// 时间处理变量
char timeStr[16] = "--:--:--"; // 当前时间字符串
char dateStr[20] = "----/--/--"; // 日期字符串
char weekStr[10] = "---"; // 星期字符串
unsigned long lastTimeUpdate = 0; // 上次时间更新时间
time_t ntpSyncTime = 0; // NTP同步时的时间戳（秒）
unsigned long ntpSyncMillis = 0; // NTP同步时的系统毫秒数
unsigned long systemStartMillis = 0; // 系统启动时间

// 状态机变量
unsigned long stateStartTime = 0; // 状态开始时间（毫秒）
unsigned long stateDuration = 0; // 当前状态持续时间（毫秒）
unsigned long remainingTime = 0; // 剩余时间（毫秒）

// 显示模式变量
int displayMode = 0; // 0: 红绿灯信息, 1: 时间信息
unsigned long lastModeSwitchTime = 0; // 上次切换显示模式的时间
const unsigned long MODE_SWITCH_INTERVAL = 60000; // 60秒切换一次显示模式

// 状态持续时间配置（毫秒）
const unsigned long STATE_DURATIONS[] = {
  5000, // 红灯持续时间 (5秒)
  7000, // 绿灯持续时间 (7秒)
  3000  // 黄灯持续时间 (3秒)
};

// 显示更新标志
bool updateDisplayFlag = true;
bool immediateDisplayUpdate = false; // 立即刷新标志
unsigned long lastDisplayUpdate = 0; // 上次显示更新时间

void setup() {
  Serial.begin(115200);
  while (!Serial); // 等待串口连接
  pinMode(RED_PIN, OUTPUT);
  pinMode(YELLOW_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  u8g2.begin();
  u8g2.setFont(u8g2_font_wqy12_t_gb2312); // 使用兼容性最好的中文字体
  systemStartMillis = millis(); // 记录系统启动时间
  Serial.println("系统启动：红绿灯控制模块已激活");
  
  // 初始化按钮状态
  buttonState = digitalRead(BUTTON_PIN);
  lastButtonState = buttonState;
  
  // 设置初始状态
  setTrafficLights(RED_STATE);
  
  // 初始化显示模式切换时间
  lastModeSwitchTime = millis();
  
  connectToWiFi();
  syncTime();
}

void loop() {
  unsigned long currentMillis = millis();
  
  // 1. 处理按钮
  handleButtonPress();
  
  // 2. 更新网络状态
  if (currentMillis - lastWiFiCheck > 10000) {
    lastWiFiCheck = currentMillis;
    checkWiFiStatus();
  }
  
  // 3. 更新时间显示（每秒一次）
  if (currentMillis - lastTimeUpdate >= 1000) {
    lastTimeUpdate = currentMillis;
    updateLocalTime();
    updateDisplayFlag = true; // 需要更新显示
  }
  
  // 4. 状态机更新（每10ms一次）
  static unsigned long lastStateUpdate = 0;
  if (currentMillis - lastStateUpdate >= 10) {
    lastStateUpdate = currentMillis;
    
    // 计算剩余时间
    if (stateStartTime + stateDuration > currentMillis) {
      remainingTime = stateStartTime + stateDuration - currentMillis;
    } else {
      remainingTime = 0;
    }
    
    // 检查状态切换
    if (!manualMode && remainingTime == 0) {
      switch (currentState) {
        case RED_STATE: 
          setTrafficLights(GREEN_STATE);
          break;
        case GREEN_STATE: 
          setTrafficLights(YELLOW_STATE);
          break;
        case YELLOW_STATE: 
          setTrafficLights(RED_STATE);
          break;
      }
    }
    
    updateDisplayFlag = true; // 需要更新显示
  }
  
  // 5. 显示模式切换（每分钟切换一次）
  if (currentMillis - lastModeSwitchTime >= MODE_SWITCH_INTERVAL) {
    displayMode = (displayMode + 1) % 2; // 在0和1之间切换
    lastModeSwitchTime = currentMillis;
    immediateDisplayUpdate = true;
    Serial.print("切换显示模式: ");
    Serial.println(displayMode == 0 ? "红绿灯信息" : "时间信息");
  }
  
  // 6. 更新显示（立即刷新或每20ms一次）
  if (updateDisplayFlag || immediateDisplayUpdate) {
    if (immediateDisplayUpdate || (currentMillis - lastDisplayUpdate >= 20)) {
      updateDisplay();
      lastDisplayUpdate = currentMillis;
      updateDisplayFlag = false;
      immediateDisplayUpdate = false;
    }
  }
}

void connectToWiFi() {
  Serial.println("连接WiFi...");
  displayFullScreenMessage("连接WiFi...");
  WiFi.begin(ssid, password);
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  wifiConnected = (WiFi.status() == WL_CONNECTED);
  if (wifiConnected) {
    Serial.println("\nWiFi连接成功!");
    Serial.print("IP地址: ");
    Serial.println(WiFi.localIP());
    wifiRSSI = WiFi.RSSI();
  } else {
    Serial.println("\nWiFi连接失败，使用内部时钟");
    displayFullScreenMessage("WiFi连接失败");
    delay(2000);
  }
}

void checkWiFiStatus() {
  if (WiFi.status() != WL_CONNECTED && wifiConnected) {
    Serial.println("WiFi连接断开!");
    wifiConnected = false;
    timeSynced = false;
  }
  else if (WiFi.status() == WL_CONNECTED && !wifiConnected) {
    Serial.println("WiFi重新连接!");
    wifiConnected = true;
    syncTime();
  }
  if (wifiConnected) {
    wifiRSSI = WiFi.RSSI();
  }
}

void syncTime() {
  if (!wifiConnected) {
    Serial.println("无法同步时间: WiFi未连接");
    timeSynced = false;
    return;
  }
  
  Serial.println("同步网络时间...");
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  timeSynced = false; // 标记为待验证
}

void updateLocalTime() {
  // 非阻塞式时间同步检查
  static unsigned long lastTimeSyncCheck = 0;
  unsigned long currentMillis = millis();
  
  if (wifiConnected && !timeSynced && currentMillis - lastTimeSyncCheck > 5000) {
    lastTimeSyncCheck = currentMillis;
    struct tm timeinfo;
    if (getLocalTime(&timeinfo, 100)) { // 100ms超时
      ntpSyncTime = mktime(&timeinfo);
      ntpSyncMillis = currentMillis;
      timeSynced = true;
      Serial.println("时间同步成功!");
    }
  }
  
  if (!timeSynced) {
    strcpy(timeStr, "--:--:--");
    strcpy(dateStr, "----/--/--");
    strcpy(weekStr, "---");
    return;
  }
  
  // 更精确的时间计算，避免跳秒
  time_t currentTime = ntpSyncTime + (currentMillis - ntpSyncMillis) / 1000;
  unsigned long millisInSecond = (currentMillis - ntpSyncMillis) % 1000;
  
  // 确保每秒只更新一次
  static unsigned long lastSecond = 0;
  struct tm *timeinfo = localtime(&currentTime);
  
  if (timeinfo) {
    // 只有在秒数变化时才更新时间字符串
    if (timeinfo->tm_sec != lastSecond) {
      lastSecond = timeinfo->tm_sec;
      strftime(timeStr, sizeof(timeStr), "%H:%M:%S", timeinfo);
      strftime(dateStr, sizeof(dateStr), "%Y/%m/%d", timeinfo);
      strftime(weekStr, sizeof(weekStr), "%a", timeinfo);
    }
  } else {
    strcpy(timeStr, "--:--:--");
    strcpy(dateStr, "----/--/--");
    strcpy(weekStr, "---");
  }
}

void handleButtonPress() {
  int reading = digitalRead(BUTTON_PIN);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        manualMode = !manualMode;
        if (manualMode) {
          Serial.println("手动模式激活");
        } else {
          Serial.println("自动模式激活");
          setTrafficLights(currentState);
        }
        immediateDisplayUpdate = true; // 需要立即刷新显示
      }
    }
  }
  lastButtonState = reading;
}

// 设置交通灯状态
void setTrafficLights(TrafficLightState newState) {
  // 关闭所有灯
  digitalWrite(RED_PIN, LOW);
  digitalWrite(YELLOW_PIN, LOW);
  digitalWrite(GREEN_PIN, LOW);
  
  // 设置新状态
  currentState = newState;
  
  // 开启对应的灯
  switch (currentState) {
    case RED_STATE:
      digitalWrite(RED_PIN, HIGH);
      break;
    case GREEN_STATE:
      digitalWrite(GREEN_PIN, HIGH);
      break;
    case YELLOW_STATE:
      digitalWrite(YELLOW_PIN, HIGH);
      break;
  }
  
  // 重置状态计时器
  stateStartTime = millis();
  stateDuration = STATE_DURATIONS[currentState];
  
  // 重置剩余时间
  remainingTime = stateDuration;
  
  // 立即同步显示状态
  displayState = currentState;
  
  Serial.print("状态切换至: ");
  switch (currentState) {
    case RED_STATE: Serial.println("红灯"); break;
    case GREEN_STATE: Serial.println("绿灯"); break;
    case YELLOW_STATE: Serial.println("黄灯"); break;
  }
  
  // 强制立即更新显示
  immediateDisplayUpdate = true;
}

void updateDisplay() {
  u8g2.firstPage();
  do {
    // 顶部WiFi状态
    u8g2.setFont(u8g2_font_6x10_tr);
    if (wifiConnected) {
      drawWiFiIcon(110, 2, wifiRSSI);
    } else {
      drawDisconnectedIcon(110, 2);
    }
    
    // 根据显示模式绘制不同内容
    if (displayMode == 0) {
      // 模式0: 红绿灯信息
      drawTrafficLightInfo();
    } else {
      // 模式1: 时间信息
      drawTimeInfo();
    }
  } while (u8g2.nextPage());
}

void drawTrafficLightInfo() {
  // 模式指示器
  const uint8_t* modeStr = manualMode ? MANUAL_MODE : AUTO_MODE;
  u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  u8g2.drawUTF8(24, 10, (char*)modeStr); // 固定位置显示

  // 红绿灯状态（中文）
  const uint8_t* stateStr = RED_CHINESE;
  switch (displayState) {
    case GREEN_STATE: stateStr = GREEN_CHINESE; break;
    case YELLOW_STATE: stateStr = YELLOW_CHINESE; break;
  }
  
  // 显示状态
  u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  u8g2.drawUTF8(44, 35, (char*)stateStr); // 固定位置显示

  // 计算剩余秒数（向上取整）
  unsigned int remainingSeconds = (remainingTime + 999) / 1000;
  
  // 显示倒计时
  char secStr[8];
  sprintf(secStr, "%d s", remainingSeconds);
  
  u8g2.setFont(u8g2_font_7x14B_tr);
  u8g2.setCursor(50, 55); // 固定位置显示
  u8g2.print(secStr);
}

void drawTimeInfo() {
  // 中部时间（大字体）
  u8g2.setFont(u8g2_font_7x14B_tr);
  int timeWidth = u8g2.getStrWidth(timeStr);
  u8g2.setCursor((128 - timeWidth) / 2, 25);
  u8g2.print(timeStr);

  // 日期显示
  u8g2.setFont(u8g2_font_7x14_tr);
  int dateWidth = u8g2.getStrWidth(dateStr);
  u8g2.setCursor((128 - dateWidth) / 2, 45);
  u8g2.print(dateStr);

  // 星期显示
  u8g2.setFont(u8g2_font_7x14_tr);
  int weekWidth = u8g2.getStrWidth(weekStr);
  u8g2.setCursor((128 - weekWidth) / 2, 64);
  u8g2.print(weekStr);
}

void drawWiFiIcon(int x, int y, int rssi) {
  int bars = 1;
  if (rssi > -55) bars = 4;
  else if (rssi > -65) bars = 3;
  else if (rssi > -75) bars = 2;
  
  // 绘制WiFi信号强度指示器
  if (bars >= 1) u8g2.drawCircle(x + 5, y + 5, 4, U8G2_DRAW_UPPER_RIGHT);
  if (bars >= 2) u8g2.drawCircle(x + 5, y + 5, 3, U8G2_DRAW_UPPER_RIGHT);
  if (bars >= 3) u8g2.drawCircle(x + 5, y + 5, 2, U8G2_DRAW_UPPER_RIGHT);
  if (bars >= 4) u8g2.drawCircle(x + 5, y + 5, 1, U8G2_DRAW_UPPER_RIGHT);
}

void drawDisconnectedIcon(int x, int y) {
  u8g2.drawCircle(x + 5, y + 5, 4, U8G2_DRAW_UPPER_RIGHT);
  u8g2.drawCircle(x + 5, y + 5, 2, U8G2_DRAW_UPPER_RIGHT);
  u8g2.drawLine(x, y, x + 10, y + 10);
  u8g2.drawLine(x, y + 10, x + 10, y);
}

void displayFullScreenMessage(const char* msg) {
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_wqy12_t_gb2312);
    int msgWidth = u8g2.getUTF8Width(msg);
    u8g2.setCursor((128 - msgWidth) / 2, 32);
    u8g2.print(msg);
  } while (u8g2.nextPage());
}